﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutoTest.Common.UtilsHelper
{
    /// <summary>
    /// 数组帮助类
    /// </summary>
    public class CollectionHelper
    {
        /// <summary>
        /// 同步分页执行
        /// </summary>
        /// <typeparam name="ParamT"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="paramsList"></param>
        /// <param name="threadExcute"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public static List<T> PageExcute<ParamT, T>(List<ParamT> paramsList, Func<List<ParamT>, T> excute, int pageSize = 1000)
        {
            var dataList = new List<T>();
            if (paramsList.Count > pageSize)
            {
                int pageIndex = 1;
                int pageCount = (int)Math.Ceiling(paramsList.Count * 1.0M / pageSize);
                do
                {
                    var rangeFilter = paramsList.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                    var data = excute(rangeFilter);
                    if (data != null) dataList.Add(data);
                    pageIndex++;
                } while (pageIndex <= pageCount);
            }
            return dataList;
        }

        /// <summary>
        /// 同步分页执行
        /// </summary>
        /// <typeparam name="ParamT">参数对象</typeparam>
        /// <typeparam name="T">返回对象</typeparam>
        /// <param name="paramsList">数组列表</param>
        /// <param name="threadExcute">执行方法</param>
        /// <param name="pageSize">分页数量</param>
        /// <returns></returns>
        public static async Task<List<T>> PageExcuteAsync<ParamT, T>(List<ParamT> paramsList, Func<List<ParamT>, Task<T>> tasExcuteAsync, int pageSize = 1000)
        {
            var taskList = new List<Task<T>>();
            if (paramsList.Count > pageSize)
            {
                int pageIndex = 1;
                int pageCount = (int)Math.Ceiling(paramsList.Count * 1.0M / pageSize);
                do
                {
                    var rangeFilter = paramsList.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                    taskList.Add(tasExcuteAsync(rangeFilter));
                    pageIndex++;
                } while (pageIndex <= pageCount);
            }
            var taskResult = await Task.WhenAll(taskList);
            return [.. taskResult];
        }
        /// <summary>
        /// 多线程执行
        /// </summary>
        /// <typeparam name="ParamT"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="paramsList"></param>
        /// <param name="threadExcute">线程执行方法</param>
        /// <param name="maxThread">最大线程数</param>
        /// <param name="threadDealSize">每个线程处理数量</param>
        /// <returns></returns>
        public static async Task<List<T>> ThreadPageExcuteAsync<ParamT, T>(List<ParamT> paramsList, Func<List<ParamT>, T> threadExcute, int maxThread, int threadDealSize = 10000)
        {
            int recordCount = paramsList.Count;
            int countPerThread = threadDealSize;
            if (recordCount > countPerThread * maxThread)
            {
                countPerThread = (int)Math.Ceiling(recordCount * 1.0M / maxThread);
            }

            var taskList = new List<Task<List<T>>>();
            var threadStart = 0;

            for (int i = 0; i < maxThread && threadStart < paramsList.Count; i++)
            {
                threadStart = i * countPerThread;
                int pageEnd = threadStart + countPerThread;
                var rangeFilterList = paramsList.Skip(threadStart).Take(countPerThread).ToList();
                if (rangeFilterList.Count > 0)
                {
                    var task = Task.Factory.StartNew((state) =>
                    {
                        var threadData = new List<T>();
                        if (state is not List<ParamT> threadRangeList || threadRangeList.Count == 0) return [];

                        for (int idex = 0; idex < threadRangeList.Count; idex += threadDealSize)
                        {
                            var oneData = threadRangeList.Skip(idex).Take(threadDealSize).ToList();
                            var onReturData = threadExcute(oneData);

                            if (onReturData != null) threadData.Add(onReturData);
                        }
                        return threadData;

                    }, rangeFilterList);
                    taskList.Add(task);
                }
            }
            var taskResultList = await Task.WhenAll(taskList);
            return taskResultList.SelectMany(t => t).ToList();
        }

        /// <summary>
        /// 多线程异步执行
        /// </summary>
        /// <typeparam name="ParamT"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="filterLis"></param>
        /// <param name="threadQueryActionAsync"></param>
        /// <param name="maxThread"></param>
        /// <param name="threadDealSize"></param>
        /// <returns></returns>
        public static async Task<List<T>> ThreadPageExcuteAsync<ParamT, T>(List<ParamT> filterLis, Func<List<ParamT>, Task<List<T>>> threadExcuteAsync, int maxThread, int threadDealSize = 10000)
        {
            int recordCount = filterLis.Count;
            int countPerThread = threadDealSize;
            if (recordCount > countPerThread * maxThread)
            {
                countPerThread = (int)Math.Ceiling(recordCount * 1.0M / maxThread);
            }

            var taskList = new List<Task<Task<List<T>>>>();
            var threadStart = 0;

            //单个一次一次请求效率不高，所以这里我打算开多线程处理
            for (int i = 0; i < maxThread && threadStart < filterLis.Count; i++)
            {
                threadStart = i * countPerThread;
                int pageEnd = threadStart + countPerThread;
                var rangeFilterList = filterLis.Skip(threadStart).Take(countPerThread).ToList();
                if (rangeFilterList.Any())
                {
                    var task = Task.Factory.StartNew(async (state) =>
                    {
                        var threadData = new List<T>();
                        if (state is List<ParamT> list && list.Count > 0)
                        {
                            for (int idex = 0; idex < list.Count; idex += threadDealSize)
                            {
                                var oneData = list.Skip(idex).Take(threadDealSize).ToList();
                                var onReturData = await threadExcuteAsync(oneData);
                                if (onReturData?.Count > 0)
                                {
                                    threadData.AddRange(onReturData);
                                }
                            }
                        }
                        return threadData;
                    }, rangeFilterList);
                    taskList.Add(task);
                }
            }
            return (await Task.WhenAll(taskList)).SelectMany(t => t.Result).ToList();
        }
    }
}
